%{
#include <iostream>
using std::cout;
using std::endl;
#include <cstdlib>
#include <cstring>
#include <queue>
#include <list>
#include <algorithm>
#include <iterator>
using namespace std;
#include <stack>


//tentativa pra num dar erro

#define 		MENOR		1
#define 		MENIG		2
#define			MAIOR   	3
#define			MAIG		4
#define			IGUAL		5
#define			DIFER		6
#define			MAIS		1
#define			MENOS		2
#define			VEZES		1
#define			DIV		2
#define			RESTO		3
#define			AND		1
#define			NAO		2
#define			OU		3
#define			NCLASSHASH	53
#define			IDNAO		0
#define			IDPROG		1
#define			IDVAR		2
#define			IDFUNC		3
#define			NAOVAR		0
#define			TIPOINT		1
#define			TIPOBOOL	2
#define			TIPOREAL	3
#define			TIPOCHAR	4
#define 		INTEIRO		1
#define 		BOOLEANO	2
#define 		TREAL		3
#define 		CARACTERE	4


//Strings para nomes dos tipos de identificadores
char *nometipid[4] = {"IDNAO", "IDPROG", "IDVAR", "IDFUNC" };


//Strings para nomes dos tipos de variaveis
char *nometipvar[5] = {"NAOVAR", "INTEIRO", "BOOLEANO", "TREAL", "CARACTERE" };

char* escopoCorrente;

//Declaracoes para a tabela de simbolos
typedef struct celsimb celsimb;

typedef struct infoexpressao infoexpressao;
struct infoexpressao {
	int tipo;
	operando opnd;
};

typedef celsimb *simbolo;
struct celsimb {
	char *cadeia;
	int tid, tvar, ndims, dims[3];
	bool inic, ref;
	list<simbolo> listVar, listParam, listFunc; 
	simbolo escopo, prox;
};

int qualParam;
simbolo paramSimb; //utilizado para guardar o parametro mais recentemente lido, para depois guardar na lista de parametros
simbolo funcSimb; //utilizado para guardar função atual no comando retornar

bool temPrincipal = FALSE;

int numParams;
int numArgs;
/*
class pList
{
	public:
	pList( int, int );
	~pList();
	int tvar, ndims;
};

pList::pList( int var, int dims ){
	tvar = var;
	ndims = dims;
}

pList::~pList() {}
*/
simbolo tabsimb[NCLASSHASH];
simbolo simb;
int tipoCorrente;

//Prototypes to keep the compiler and baggio happy :-)

void yyerror (const char *error);
int yyparse();
int  yylex ();
void tabular();
int InicTabSimb (void);
int ImprimeTabSimb (void);
simbolo InsereSimb (char *, int, int);
int hash (char *);
simbolo ProcuraSimb (char *);
void DeclaracaoRepetida (char *s);
void TipoInadequado (char *);
void NaoDeclarado (char *);
void NaoEsperado (char *);
void Incompatibilidade (char *);
void VerificaInicRef (void);

int tab = 0;

%}



%union {
	char cadeia[255];
	int atr, valor;
	float num;
	char mander;
	infoexpressao infoexpr;
	int tipoexpr;
	simbolo simb;
	
};


%type		<infoexpr>	Expressao ExprAux1 ExprAux2 ExprAux3 ExprAux4 Termo Fator
%type		<simb>		Variavel
%token		<cadeia>	ID
%token		<valor>		CTINT
%token		<valor>		CTREAL
%token		<mander>	CTCHAR
%token		<cadeia>	CADEIA
%token 		BOOLEANO
%token 		CARACTERE
%token 		CHAMAR
%token		COMANDOS
%token		ENQUANTO
%token		ENTAO
%token		ESCREVER
%token		FALSO
%token		FAZER
%token		GLOBAIS
%token		INTEIRO
%token		LER
%token		LOCAIS
%token		NENHUM
%token		PARA
%token		PRINCIPAL
%token		PROGRAMA
%token		PROTOTIPOS
%token		REAL
%token		RETORNAR
%token		SE
%token		SENAO
%token		VERDADE
%token		OPREL
%token		OPOR
%token		OPAND
%token		OPNOT
%token		OPAD
%token		OPMULT
%token		OPNEG
%token		ABPAR
%token		FPAR
%token		ABCOL
%token		FCOL
%token		ABTRIP
%token		FTRIP
%token		ABCHAV
%token		FCHAV
%token		PVIRG
%token		VIRG
%token		DPONTS
%token		ATRIB
%token		INVAL

%%
Prog		:	PROGRAMA { cout << "programa "; escopoCorrente = "global##"; } ID 
			{cout << $3 << endl; inicTabSimb(); InsereSimb( $1, IDPROG, NAOVAR);} 
			ABTRIP { cout << "{{{"; tab++; cout << endl; } DeclGlobs DeclProts ListMods 
			{ tab--; cout << endl; } FTRIP 
			{ 	
				tabular(); cout << "}}}" << endl; 
				if (!temPrincipal) 
					cout << "\n\n****   O programa não possui função principal   ****\n" << endl;
				VerificaInicRef ();
				ImprimeTabSimb(); 
			}
			;
DeclGlobs 	: 	/*	vazia	  */
		|	{ tabular(); } GLOBAIS DPONTS { cout << "globais:"; tab++; cout << endl; } ListDecl 
			{ cout << endl; tab--; }
			;
ListDecl	:	Declaracao
		|	ListDecl Declaracao
			;
Declaracao	:	{ tabular(); } Tipo DPONTS { cout << ": "; } ListElemDecl PVIRG { cout << ";" << endl; }
			;
Tipo		:	INTEIRO { cout << "int"; tipoCorrente = TIPOINT; }
		|	REAL { cout << "real"; tipoCorrente = TIPOREAL; }
		|	CARACTERE { cout << "carac"; tipoCorrente = TIPOCHAR; }
		|	BOOLEANO { cout << "booleano"; tipoCorrente = TIPOBOOL; }
		|	NENHUM { cout << "nenhum"; tipoCorrente = NAOVAR; }
			;
ListElemDecl	:	ID 
			{ 
				cout << $1; 
				simb = ProcuraSimb( $1 ); 
				if ( simb != NULL && simb->escopo == ProcuraSimb(escopoCorrente) ) 
					DeclaracaoRepetida( $1 ); 
				else 
					simb = InsereSimb( $1, IDVAR, tipoCorrente, escopoCorrente ); simb->ndims = 0; 
			} 
			Dimens
			;
Dimens		:	
		|	ABCOL { cout << "["; } ListDims FCOL { cout << "]"; }
			;
ListDims	:	CTINT 
			{ 
				cout << $1; 
				simb->ndims = 1; 
				simb->dims[1] = $1; 
				if ( $1 <= 0 ) 
					esperado ( "Valor inteiro positivo" ); 
			}
		|	CTINT { cout << $1; if ( $1 <= 0 ) esperado ( "Valor Inteiro Positivo" );} 
			VIRG { cout << ","; } CTINT
			{
				cout << $5; 
				simb->ndims = 2; 
				simb->dims[1] = $1; 
				simb->dims[2] = $5; 
				if ( $5 <= 0 )
					esperado ( "Valor Inteiro Positivo" );
			}
			;
DeclProts	:	/*	vazia	  */
		|	{ tabular(); } PROTOTIPOS DPONTS { cout << "prototipos: "<< endl; tab++; } 
			ListProts { cout << endl; tab--; }
			;
ListProts	:	Prototipo
		|	ListProts Prototipo
			;
Prototipo	:	{ tabular(); } Tipo DPONTS { cout << ": "; } ID 
			{ 
				cout << $5; 
				if ( ProcuraSimb( $4) != NULL ) 
					DeclaracaoRepetida( $1 );
				else if (strcmp($4, "principal") || strcmp($4, "global##")) 
					NomeDeFuncaoNaoAutorizado();
 				else 
					simb = InsereSimb( $4, IDFUNC, tipoCorrente, "global##" );  
				escopoCorrente = $5;
			}
 			ABPAR { cout << "( "; qualParam = 0;} TParams FPAR { cout << " )"; } PVIRG 
			{ cout << ";" << endl; escopoCorrente = "global##";}
			;
TParams		:	{simb->listParam = NULL;}
		|	ListTParam
			;
ListTParam	:	TParametro { simb->listParam.push_back($1);}
		| 	ListTParam VIRG { cout << ", "; } TParametro
			{simb->listParam.push_back($4);}
			;
TParametro	:	Tipo { tipoCorrente = $1; } DimParam 
			{$<simb>$ = InsereSimbParam(IDVAR, tipoCorrente, escopoCorrente, qualParam++); }
			;
DimParam	:	{ simb->paramList.push( new pList( tipoCorrente, 0 );  $$ = 0;}
		|	ABCOL { cout << "["; simb->paramList.push( new pList( tipoCorrente, 1 ); } FCOL { cout << "]";  $$ =1;}
		|	ABCOL VIRG FCOL { cout << "[,]"; simb->paramList.push( new pList( tipoCorrente, 1 ); $$ = 2;}
		;
ListMods	:	Modulo
		|	ListMods Modulo
			;
Modulo		:	Cabecalho ABCHAV { tab++; cout << "{" << endl; } DeclLocs Cmds { tab--; tabular(); } 
			FCHAV { cout << "}" << endl << endl; escopoCorrente = "global##";}
			;
Cabecalho	:	{ tabular(); } PRINCIPAL 
			{ 
				cout << "principal"; 
				escopoCorrente = "principal"; 
				if (temPrincipal) 
					cout << "\n\n****   Deve haver somente uma função principal!!!   ****\n" << endl;
				temPrincipal = TRUE; 
			}
		|	{ tabular(); numParams = 0;} ID { funcSimb = simb = ProcuraSimb( $2 ); cout << $2; } 
			ABPAR { cout << "( "; } Params FPAR { cout <<  )"; "}
			;
Params		:	/*	vazia	   */
			{
				if (!simb->listParam.empty() ) 
					NumeroParametrosErrado( simb->cadeia );
			}
		|	ListId
			;
ListId		:	ID 
			{ 
				cout << $1; 
				numParam++; 
				if ( simb->listParam.size() != numParam ) 
					NumeroParametrosErrado( simb->cadeia ); 
			}
		|	ListId VIRG ID { cout << ", " << $3; numParam++; }
			;
DeclLocs	:
		|	{tabular();} LOCAIS DPONTS { tab++; cout << "locais: " << endl; } ListDecl { tab--; cout << endl; }
			;
Cmds		:	{tabular();} COMANDOS DPONTS {tab++; cout << "comandos: " << endl; } ListCmds { tab--; }
			;
ListCmds	:	Comando
		|	ListCmds Comando
			;
Comando		:	{tab--; tabular(); } CmdComposto { cout << endl; tab++; }
		|	{tabular(); } CmdSe 
		|	{tabular(); } CmdEnquanto 
		|	{tabular(); } CmdFazer { cout << endl; }
		|	{tabular(); } CmdPara 
		|	{tabular(); } CmdLer { cout << endl; }
		|	{tabular(); } CmdEscrever { cout << endl; }
		|	{tabular(); } CmdAtrib { cout << endl; }
		|	{tabular(); } ChamaMod { cout << endl; }
		|	{tabular(); } CmdRetornar { cout << endl; }
		|	PVIRG { cout << ";" << endl; }
			;
CmdComposto	:	ABCHAV {cout << "{\n"; tab++;} ListCmds {tab--; tabular ();} FCHAV { cout << "}"; } 
			;
CmdSenao	:		
		|	SENAO {tabular(); cout << "senao " << endl; tab++; } Comando { tab--; }
	        	; 
CmdSe		:	SE  { cout << "se "; } Expressao 
			{
				if ($3.tipo != BOOLEANO) 
					esperado ("Expressao booleana!!");
			}
			ENTAO { cout << " entao " << endl; tab++; } Comando  { tab--; } CmdSenao 
			;
CmdEnquanto	:	ENQUANTO { cout << "enquanto "; } Expressao 
			{
				if ($3.tipo != BOOLEANO) 
					esperado ("Expressao booleana!!");
			}
			FAZER { cout << " fazer " << endl; tab++; } Comando { tab--; }
			;
CmdFazer	:	FAZER { cout << "fazer" << endl; tab++; } Comando { tab--; tabular(); } 
			ENQUANTO { cout << "enquanto ";} Expressao 
			{
				if ($7.tipo != BOOLEANO) 
					esperado ("Expressao booleana!!");} PVIRG { cout << ";"; 
			} 
			;
CmdPara		:	PARA ABPAR { cout << "para( "; } Variavel 
			{ 
				if ($4.tvar != TIPOINT && $4.tvar != TIPOCHAR) 
					esperado ("Variável inteira ou caractere"); 
			} 
			ATRIB { cout << " <- "; } Expressao PVIRG { cout << "; "; } Expressao 
			{
				if ($11.tipo != BOOLEANO) 
					esperado ("Expressao booleana!!");
			}
			PVIRG {cout << "; "; } Variavel ATRIB { cout << " <- "; } Expressao
			FPAR { tab++; cout << " )" << endl; } Comando { tab--; }
			;
CmdLer		:	LER ABPAR { cout << "ler( "; } ListVar FPAR { cout << " )"; } PVIRG { cout << ";" }
			;
ListVar		:	Variavel { if ( simb != NULL ) { $1.simb->inic = TRUE;  } }
		|	ListVar VIRG { cout << ", "; } Variavel { if ( simb != NULL ) {$4.simb->inic = TRUE; } }
			;
CmdEscrever	:	ESCREVER ABPAR { cout << "escrever( "; } ListEscr FPAR PVIRG { cout << " );"; }
			;
ListEscr	:	ElemEscr
		|	ListEscr VIRG { cout << ", "; } ElemEscr
			;
ElemEscr	:	CADEIA { cout << $1 ; }
		|	Expressao
			;
ChamaMod	:	CHAMAR { cout << "chamar "; } ChamaFunc PVIRG { cout << ";"; }
			;
ChamaFunc	:	ID {simb = ProcuraSimb( $2 );} ABPAR { cout << $1 << "( "; numArgs = 0;} Argumentos FPAR { cout << ")"; }
			;
Argumentos	:	/*	vazia	   */ 
			{
				if (!simb->listParam.empty() ) 
					NumeroParametrosErrado( simb->cadeia );
			}
		|	ListExpr
			;


/*
ListId		:	ID 
			{ 
				cout << $1; 
				numParam++; 
				if ( simb->listParam.size() != numParam ) 
					NumeroParametrosErrado( simb->cadeia ); 
			}
		|	ListId VIRG ID { cout << ", " << $3; numParam++; }
			;
*/
ListExpr	:	Expressao
			{ 
				numArgs++; 
				if ( simb->listParam.size() != numArgs ) 
					NumeroParametrosErrado( simb->cadeia ); 
			}
		|	ListExpr VIRG { cout << ", "; } Expressao { numArgs++; }
			;
CmdRetornar	:	RETORNAR 
			{
				if (funcSimb->tvar != NAOVAR)
					esperado ("variavel retornada pela função");
			}
			PVIRG { cout << "retornar;"; }
		|	RETORNAR { cout << "retornar "; } Expressao 
			{
				if((funcSimb->tvar==TIPOINT || funcSimb->tvar==TIPOCHAR) && $3.tipo!=TIPOINT && $3.tipo!=TIPOCHAR)
					Incompatibilidade("Função deveria retornar expressao do tipo inteiro ou caractere");
				if (funcSimb->tvar == TIPOBOOL && $3.tipo !=BOOLEANO ) 
					Incompatibilidade("Função deveria retornar expressão booleana");
				if(funcSimb->tvar==TIPOREAL && $3.tipo!=TIPOINT && $3.tipo!=TIPOCHAR && $3.tipo!=TIPOREAL)
					Incompatibilidade("Função deveria retornar expressão do tipo inteiro, caractere ou real");
				if(funcSimb->tvar==NAOVAR)
					Incompatibilidade("Função não deveria retornar expressão");
			}
			PVIRG { cout << ";"; }
			;
CmdAtrib	:	Variavel ATRIB { cout << " <- "; } Expressao PVIRG 
			{ 
				cout << ";"; 
				if ($1.tvar == TIPOBOOL && $4.tipo !=BOOLEANO ) 
					esperado ("Expressão booleana do lado direito!");
				if (($1.tvar==TIPOCHAR || $1.tvar==TIPOINT) && $4.tipo!=TIPOINT && $4.tipo!=TIPOCHAR)
					esperado("Expressão do tipo inteiro ou caractere do lado direito");
				if($1.tvar==TIPOREAL && $4.tipo!=TIPOINT && $4.tipo!=TIPOCHAR && $4.tipo!=TIPOREAL)
					esperado("Expressão do tipo inteiro, caractere ou real do lado direito");
			}
			;
Expressao	:	ExprAux1
		|	Expressao OPOR { cout << " || "; } ExprAux1
			{
				if ($1.tipo != BOOLEANO || $4.tipo != BOOLEANO)
					Incompatibilidade("Operando improprio para operador OR");
				$$.tipo = BOOLEANO;
			 }
			;
ExprAux1	:	ExprAux2
		|	ExprAux1 OPAND { cout << " && "; } ExprAux2
			{
				if ($1.tipo != BOOLEANO || $4.tipo != BOOLEANO)
					Incompatibilidade("Operando improprio para operador AND");
				$$.tipo = BOOLEANO;
			}
			;
ExprAux2	:	ExprAux3
		|	OPNOT { cout << "!"; } ExprAux3
			{
				if ($3.tipo != BOOLEANO)
					Incompatibilidade ("Operando improprio para NOT");
				$$.tipo = BOOLEANO;
			}
			;
ExprAux3	:	ExprAux4
		|	ExprAux4 OPREL
			{ switch ( yylval.atr ) 
			  {
			  	case MENOR :
					cout << " < ";
					break;
				case MENIG :
					cout << " <= ";
					break;
				case MAIOR :
					cout << " > ";
					break;
				case MAIG :
					cout << " >= ";
					break;
				case IGUAL :
					cout << " = ";
					break;
				case DIFER :
					cout << " != ";
					break;
} }
			ExprAux4
		{
			switch ($2) {
				case MENOR: case MENIG: case MAIOR: case MAIG:
					if ($1.tipo != INTEIRO && $1.tipo != TREAL &&
					    $1.tipo != CARACTERE || $4.tipo != INTEIRO &&
					    $4.tipo != TREAL && $4.tipo != CARACTERE)
						Incompatibilidade("Operando improprio para operador relacional");
					$$.tipo = BOOLEANO;
					break;
				case IGUAL: case DIFER:
					if (($1.tipo == BOOLEANO || $4.tipo == BOOLEANO) && $1.tipo != $4.tipo)
						Incompatibilidade("Operando improprio para operador relacional");
					$$.tipo = BOOLEANO;
					break;
			}
		}
			;
ExprAux4	:	Termo
		|	ExprAux4 OPAD { 
			switch( yylval.atr )
			{
				case MAIS:
					cout << " + ";
					break;
				case MENOS:
					cout << " - ";
					break;
			} }
			Termo
			{
				if ($1.tipo != INTEIRO && $1.tipo != TREAL && $1.tipo != CARACTERE ||
				    $4.tipo != INTEIRO && $4.tipo != TREAL && $4.tipo != CARACTERE)
					Incompatibilidade("Operando improprio para operador aritmetico");
				if ($1.tipo == TREAL || $4.tipo == TREAL) 
					$$.tipo = TREAL;
				else 
					$$.tipo = INTEIRO;
			}
			;
Termo		:	Fator
		|	Termo OPMULT
			{
			switch( yylval.atr )
			{
				case VEZES:
					cout << " * ";
					break;
				case DIV:
					cout << " / ";
					break;
				case RESTO:
					cout << " % ";
					break;
			} }
			Fator
			{
				switch ($2) {
					case VEZES: case DIV:
						if ($1.tipo != INTEIRO && $1.tipo != TREAL && $1.tipo != CARACTERE || 
						    $4.tipo != INTEIRO && $4.tipo!=TREAL &&
						    $4.tipo!=CARACTERE)
							Incompatibilidade ("Operando improprio para operador aritmetico");
						if ($1.tipo == TREAL || $4.tipo == TREAL) 
							$$.tipo= TREAL;
						else 
							$$.tipo = INTEIRO;
						break;
					case RESTO:
						if ($1.tipo != INTEIRO && $1.tipo != CARACTERE ||
						    $4.tipo != INTEIRO && $4.tipo != CARACTERE)
							Incompatibilidade ("Operando improprio para operador resto");
						$$.tipo = INTEIRO;
						break;
				}
			}
         ;

Fator		: 	Variavel  	
			{     	if ($1.simb != NULL) 
				{
					$1.simb->ref = VERD;
					$$.tipo = $1.simb->tvar;
				}
			}
		|	CTINT { cout << $1; $$.tipo = TIPOINT;}
		|	CTREAL { cout << $1; $$.tipo = TIPOREAL;}
		|	CTCHAR { cout << $1; $$.tipo = TIPOCHAR;}
		|	VERDADE { cout << "verdade"; $$.tipo = TIPOBOOL;}
		|	FALSO { cout << "falso"; $$.tipo = TIPOBOOL;}
		| 	OPNEG { cout << "~"; } Fator {
			if ($3.tipo != TIPOINT && $3.tipo != TIPOREAL && $3.tipo != TIPOCHAR)
				Incompatibilidade ("Operando improprio para menos unario");
			if ($3.tipo == TIPOREAL) $$.tipo = TIPOREAL;
			else $$.tipo = TIPOINT; 
			}
		|	ABPAR { cout << "( "; } Expressao FPAR { cout << " )"; }
		|	ChamaFunc
			;
Variavel	:	ID 
			{
				cout << $1;
				simb = ProcuraSimb ($1);
				if (simb == NULL)
					NaoDeclarado ($1);
				else if (simb->tid != IDVAR)
					TipoInadequado ($1);
				$<simb>$ = simb; 
			}
			Indices 
			{
				if ($<simb>2)
					if ($<simb>2->ndims == 0) {
						if ($3 != 0)
							NaoEsperado ("Subscrito\(s)");
					}
					else if ($3 != $<simb>2->ndims)
                     				Incompatibilidade("Numero de subscritos incompativel com declaracao");
				$$.simb = $<simb>2;
			}
			;
Indices		:	{$$ = 0;}
		|	ABCOL { cout << "["; } ListInd FCOL { cout << "]"; $$ = $3;}
			;
ListInd		:	ExprAux4 {
					$$ = 1;
					if ($1.tipo != INTEIRO && $1.tipo != CARACTERE)
						Incompatibilidade("Expressao devia ser inteira ou caractere");
				}
		|	ExprAux4 {
					if ($1.tipo != INTEIRO && $1.tipo != CARACTERE)
						Incompatibilidade("Expressao devia ser inteira ou caractere");
				 }
			VIRG { cout << ","; } ExprAux4
			{
				$$ = 2;
				if ($5.tipo != INTEIRO && $5.tipo != CARACTERE)
					Incompatibilidade("Expressao devia ser inteira ou caractere");
			}
			;



%%

#include "lab2.cc"

void tabular () {
	int i;
	for (i = 1; i <= tab; i++)
   		cout << "   ";
}

int InicTabSimb () {
	int i;
	for (i = 0; i < NCLASSHASH; i++)
		tabsimb[i] = NULL;
}

/*
	ProcuraSimb: Procura na tabela de simbolos o simbolo 
contendo uma determinada cadeia; Retorna um ponteiro 
para tal simbolo se ele estiver na tabela. Caso 
contrario, retorna NULL.

	cadeia: cadeia do simbolo procurado.
 */

simbolo ProcuraSimb (char *cadeia) {
	simbolo s; int i;

	i = hash (cadeia);
	for (s = tabsimb[i]; (s!=NULL) && strcmp(cadeia, s->cadeia) &&
               s->escopo == escopoCorrente; s = s->prox);
	if (s!=NULL)
		return s;
	for (s = tabsimb[i]; (s!=NULL) && strcmp(cadeia, s->cadeia) &&
               s->escopo == "global##"; s = s->prox);
		return s;

}

/*
	InsereSimb: Insere um identificador na tabela de 
simbolos; retorna um ponteiro para o simbolo formado.
 */

simbolo InsereSimb (char *cadeia, int tid, int tvar ) {
	int i; simbolo aux, s;
	i = hash (cadeia);
	aux = tabsimb[i];
	s = tabsimb[i] = malloc (sizeof (celsimb));
	s->cadeia = malloc ((strlen(cadeia)+1) * sizeof(char));
	strcpy (s->cadeia, cadeia);
	s->tid = tid;		s->tvar = tvar;
	s->inic = FALSE;	s->ref = FALSE;
	s->escopo = procuraSimb("global##");
	s->prox = aux;		return s;
}

//POG
simbolo InsereSimb (char *cadeia, int tid, int tvar, char* escopo ) {
	int i; simbolo aux, s;
	i = hash (cadeia);
	aux = tabsimb[i];
	s = tabsimb[i] = malloc (sizeof (celsimb));
	s->cadeia = malloc ((strlen(cadeia)+1) * sizeof(char));
	strcpy (s->cadeia, cadeia);
	s->tid = tid;		s->tvar = tvar;
	s->inic = FALSE;	s->ref = FALSE;
	s->escopo = procuraSimb(escopo);
	s->prox = aux;		return s;
}


//POG2 by Baggio
simbolo InsereSimbParam (int tid, int tvar, char* escopo, int numParam ) {
	int i; simbolo aux, s;
	i = hash (cadeia);
	aux = tabsimb[i];
	s = tabsimb[i] = malloc (sizeof (celsimb));
	s->tid = tid;		s->tvar = tvar;
	s->inic = numParam;	s->ref = FALSE;
	s->escopo = procuraSimb(escopo);
	s->prox = aux;		return s;
}

/*
	Hash: funcao que determina a classe de um elemento 
na tabela de simbolos implementada por hashing
 */

int hash (char *cadeia) {
	int i, h;
	for (h = i = 0; cadeia[i]; i++) {
		h += cadeia[i];}
	h = h % NCLASSHASH;
	return h;
}


//ImprimeTabSimb: Imprime o conteudo da tabela de simbolos
ImprimeTabSimb () {
	int i; simbolo s;

	printf ("\n\n   TABELA  DE  SIMBOLOS:\n\n");
	for (i = 0; i < NCLASSHASH; i++)
		if (tabsimb[i]) {
			printf ("Classe %d:\n", i);
			for (s = tabsimb[i]; s!=NULL; s = s->prox){
				printf ("  (%s, %s", s->cadeia, 
					nometipid[s->tid]);
				if (s->tid == IDVAR)
					printf (", %s, %d, %d", 
						nometipvar[s->tvar], s->inic, s->ref);
				printf(")\n");
			}
		}
}


//Testes semanticos
void DeclaracaoRepetida (char *s) {
	printf ("\n\n***** Declaracao Repetida: %s *****\n\n", s);
}

void NaoDeclarado (char *s) {
	printf ("\n\n***** Identificador Nao Declarado: %s *****\n\n", s);
}

void TipoInadequado (char *s) {
	printf ("\n\n***** Identificador de Tipo Inadequado: %s *****\n\n", s);
}


void esperado( char *s )
{
	printf( "\n\n***** Esperado: %s *****\n\n", s );
}

void NaoEsperado (char *s) {
	printf ("\n\n***** Nao Esperado: %s *****\n\n", s);
}

void Incompatibilidade (char *s) {
	printf ("\n\n***** Incompatibilidade: %s *****\n\n", s);
}

void NomeDeFuncaoNaoAutorizado ()
{
	cout << "\n\n***** Este nome de função não é permitido! *****\n\n";
}

void NumeroParametrosErrado( char *s)
{
   cout << "\n\n**** Número de parâmetros na função " << s << " está incorreto. *****\n\n";
}

void VerificaInicRef () {
	int i; simbolo s;

	printf ("\n");
	for (i = 0; i < NCLASSHASH; i++)
		if (tabsimb[i]) {
			for (s = tabsimb[i]; s!=NULL; s = s->prox){
				if (s->tid == IDVAR) {
					if (s->inic == FALS)
						printf ("%s: Nao Inicializada\n", s->cadeia);
					if (s->ref == FALS)
						printf ("%s: Nao Referenciada\n", s->cadeia);
				}
			}
		}
}

